package com.etc.security.filter;

import java.io.IOException;
import java.util.*;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.etc.security.config.JwtTokenUtils;
import com.etc.security.domain.JwtUser;
import com.etc.security.domain.LoginUser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import com.etc.common.Code;
import com.etc.common.CodeMessage;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.servlet.support.RequestContext;


/**
 * Filename:    JWTAuthenticationFilter.java
 * Description:   登陆用户密码验证过滤器，前置
 * Copyright:   Copyright (c) 2018-2019 All Rights Reserved.
 * Company:     chinasofti.com Inc.
 *
 * @author: mazheng
 * @version: 1.0
 * Create at:   2020年3月4日 下午3:37:42
 * <p>
 * Modification History:
 * Date         Author      Version     Description
 * ------------------------------------------------------------------
 * 2020年3月4日      mazheng      1.0         1.0 Version
 */
public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
    private static final Logger logger = LoggerFactory.getLogger(JWTAuthenticationFilter.class);
    private ThreadLocal<Integer> rememberMe = new ThreadLocal<>();
    private AuthenticationManager authenticationManager;

    public JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
        super.setFilterProcessesUrl("/admin/login");
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request,
                                                HttpServletResponse response) throws AuthenticationException {

        WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(request.getServletContext());

        // 从输入流中获取到登录的信息
        LoginUser loginUser = null;
        try {
            // json参数
            loginUser = new ObjectMapper().readValue(request.getInputStream(), LoginUser.class);
        } catch (Exception e) {
            logger.warn("request is not payload json", e);
            loginUser = new LoginUser(Optional.ofNullable(request.getParameter("username")).map(item -> String.valueOf(item)).orElse(null),
                    Optional.ofNullable(request.getParameter("password")).map(item -> String.valueOf(item)).orElse(null),
                    Optional.ofNullable(request.getParameter("rememberMe")).map(item -> Integer.valueOf(item)).orElse(null)
            );
        }

//        LoginUser loginUser = new LoginUser(request.getParameter("username"),request.getParameter("password"), Integer.valueOf(request.getParameter("rememberMe")));
        rememberMe.set(loginUser.getRememberMe());
        return authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(loginUser.getUsername(), loginUser.getPassword(), new ArrayList<>())
        );
    }

    // 成功验证后调用的方法
    // 如果验证成功，就生成token并返回
    @Override
    protected void successfulAuthentication(HttpServletRequest request,
                                            HttpServletResponse response,
                                            FilterChain chain,
                                            Authentication authResult) throws IOException, ServletException {

        JwtUser jwtUser = (JwtUser) authResult.getPrincipal();
        System.out.println("jwtUser:" + jwtUser.toString());
        boolean isRemember = (rememberMe.get() == null ? 0 : 1) == 1;

        StringBuilder roles = new StringBuilder();
        Collection<? extends GrantedAuthority> authorities = jwtUser.getAuthorities();
        for (GrantedAuthority authority : authorities) {
            roles.append(authority.getAuthority());
        }

        String token = JwtTokenUtils.createToken(jwtUser.getUsername(), roles.toString(), isRemember);
//        String token = JwtTokenUtils.createToken(jwtUser.getUsername(), false);
        // 返回创建成功的token
        // 但是这里创建的token只是单纯的token
        // 按照jwt的规定，最后请求的时候应该是 `Bearer token`
        response.setHeader("token", JwtTokenUtils.TOKEN_PREFIX + token);
        // cookie方式设置
        Cookie newVisitorCookie = new Cookie(JwtTokenUtils.TOKEN_PREFIX, JwtTokenUtils.TOKEN_PREFIX + token);
        newVisitorCookie.setMaxAge((int) (JwtTokenUtils.EXPIRATION / 60));
        // 二级域名设置
//        newVisitorCookie.setDomain(".google.com");
        response.addCookie(newVisitorCookie);

        Map map = new HashMap();
        map.put("code", "200");
        map.put("token", JwtTokenUtils.TOKEN_PREFIX + token);
        map.put("username", jwtUser.getUsername());
        map.put("roles", jwtUser.getAuthorities());
        map.put("message", "login success");
        map.put("avatar", "TODO");
        map.put("introduction", "TODO");


        ObjectMapper mapper = new ObjectMapper(); //转换器
        //测试01：对象--json
        String json = mapper.writeValueAsString(map); //将对象转换成json
        response.getWriter().write(json);
    }

    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");

        if (failed instanceof BadCredentialsException) {

            response.getWriter().write(new ObjectMapper().writeValueAsString(CodeMessage.faild(Code.FAIL, "ユーザ名存在しない")));
        } else if (failed instanceof UsernameNotFoundException) {
            response.getWriter().write(new ObjectMapper().writeValueAsString(CodeMessage.faild(Code.FAIL, "パスワードが違います")));
        } else {
            response.getWriter().write(new ObjectMapper().writeValueAsString(CodeMessage.faild(Code.FAIL, failed.getMessage())));
        }
    }
}
